// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Author: Markus Gutschke

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#include "base64.h"
#include "check.h"
#include "connection.h"
#include "email_print_job.h"
#include "hashmap.h"
#include "http.h"
#include "net.h"
#include "stringprintf.h"


static void dialog(struct Connection *conn, const char *fmt, ...) {
  // Drain any data that might still be unread
  char buf[256];
  size_t sz;
  if (fmt) {
    while (connIsReadable(conn, 0)) {
      check((sz = connRead(conn, buf, sizeof(buf))) >= 0);
      if (!sz) {
        break;
      }
    }
  
    // Write SMTP protocol data
    va_list ap;
    va_start(ap, fmt);
    char *msg = vStringPrintf(NULL, fmt, ap);
    va_end(ap);
    size_t len = strlen(msg);
    check(connWrite(conn, msg, len) == len);
    free(msg);
  }

  // Read at least some of the reply
  do {
    check((sz = connRead(conn, buf, sizeof(buf))) >= 0);
  } while (sz > 0 && connIsReadable(conn, 1));
}

void emailPrintJob(struct OAuth2 *oauth2, struct JSON *job,
                   const char *from, const char *to) {
  check(job->type == J_OBJECT);
  const struct JSON *urlObj, *titleObj;
  check(urlObj = (struct JSON *)getFromHashMap(&job->obj, "fileUrl"));
  check(urlObj->type == J_STRING);
  check(titleObj = (struct JSON *)getFromHashMap(&job->obj, "title"));
  check(titleObj->type == J_STRING);
  struct Connection cloudprint;
  check(openHTTPSocket(&cloudprint, "GET", urlObj->str,
                       "Accept: application/pdf\r\n",
                       oauth2, NULL, M_MULTIPART) == 200);
  char *at;
  check(at = strrchr(to, '@'));
  int fd;
  check((fd = openSocket(++at, "smtp")) >= 0);
  struct Connection mail;
  initConnection(&mail, fd);
  check(at = strrchr(from, '@'));
  dialog(&mail, NULL);
  dialog(&mail, "EHLO %s\r\n", ++at);
  dialog(&mail, "MAIL FROM: <%s>\r\n", from);
  dialog(&mail, "RCPT TO: <%s>\r\n", to);
  dialog(&mail, "DATA\r\n");
  static const char *subject, *msg;
  check(subject = httpHeaderEncoding(titleObj->str));
  msg = stringPrintf(NULL,
    "From: <%s>\r\n"
    "To: <%s>\r\n"
    "Subject: CloudPrint: %s\r\n"
    "MIME-Version: 1.0\r\n"
    "Content-Type: application/pdf; x-unix-mode=0644; "
                  "name=\"cloudprint.pdf\"\r\n"
    "Content-Transfer-Encoding: base64\r\n"
    "Content-Disposition: inline; filename=\"cloudprint.pdf\"\r\n"
    "\r\n",
    from, to, subject);
  size_t msg_len = strlen(msg);
  free((void *)subject);
  check(connWrite(&mail, msg, msg_len) == msg_len);
  free((void *)msg);
  for (;;) {
    char raw[54], b64[(sizeof(raw) + 2)/3*4 + 3];
    ssize_t len = 0, sz;
    do {
      check((sz = connRead(&cloudprint, raw + len, sizeof(raw)-len)) >= 0);
      len += sz;
    } while (sz && len < sizeof(raw));
    sz = b64encode(b64, raw, len);
    strcpy(b64 + sz, "\r\n");
    check(connWrite(&mail, b64, sz + 2) == sz + 2);
    if (!sz) {
      break;
    }
  }
  dialog(&mail, ".\r\n");
  dialog(&mail, "QUIT\r\n");
  destroyConnection(&cloudprint);
  destroyConnection(&mail);
}
